Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Legacy/overview auth! #430

Merged
merged 12 commits into from
Nov 5, 2024
Merged

Legacy/overview auth! #430

merged 12 commits into from
Nov 5, 2024

Conversation

Andreass2
Copy link
Collaborator

@Andreass2 Andreass2 commented Nov 4, 2024

Description

Adds pdp request for correct auth for legacy correspondence overview
Introduces some new attributes to the response object needed by A2

Related Issue(s)

Verification

  • Your code builds clean without any errors or warnings
  • Manual testing done (required)
  • Relevant automated test added (if you find this hard, leave it and we'll help out)
  • All tests run green

Documentation

  • User documentation is updated with a separate linked PR in altinn-studio-docs. (if applicable)

Summary by CodeRabbit

  • New Features

    • Introduced a new LegacyCorrespondenceOverviewMapper for enhanced data mapping.
    • Added LegacyCorrespondenceOverviewExt class with additional properties for correspondence details.
    • New error handling for invalid party IDs.
    • Expanded user access checks with the new CheckUserAccessAndGetMinimumAuthLevel method.
    • Enhanced response structure in LegacyGetCorrespondenceOverviewResponse with new properties.
    • Added CheckMigrationAccess method for improved access validation.
  • Bug Fixes

    • Improved error handling and response formulation in the correspondence overview handler.
    • Corrected property naming for MinimumAuthenticationLevel for consistency.
  • Documentation

    • Updated error definitions to include specific cases for better clarity.
  • Chores

    • Refactored existing methods for enhanced functionality and clarity in user access validation.

Copy link
Contributor

coderabbitai bot commented Nov 4, 2024

📝 Walkthrough
📝 Walkthrough

Walkthrough

The pull request includes several modifications primarily focused on the LegacyCorrespondenceController, where the CorrespondenceOverviewMapper is renamed to LegacyCorrespondenceOverviewMapper. New classes and methods are introduced to enhance the mapping and response handling for legacy correspondence data. Key additions include the LegacyCorrespondenceOverviewExt class and the LegacyGetCorrespondenceOverviewResponse class, both designed to extend functionality. Additionally, new error handling mechanisms and service registrations are implemented to support the updated logic without altering existing control flows.

Changes

File Path Change Summary
src/Altinn.Correspondence.API/Controllers/LegacyCorrespondenceController.cs Renamed CorrespondenceOverviewMapper to LegacyCorrespondenceOverviewMapper and updated mapping logic in methods. Updated return type and added comments in GetCorrespondenceHistory.
src/Altinn.Correspondence.API/Mappers/LegacyCorrespondenceOverviewMapper.cs Introduced LegacyCorrespondenceOverviewMapper class with MapToExternal method for mapping legacy correspondence data.
src/Altinn.Correspondence.API/Models/LegacyCorrespondenceOverviewExt.cs Added LegacyCorrespondenceOverviewExt class with new properties for legacy correspondence overview.
src/Altinn.Correspondence.Application/DependencyInjection.cs Updated AddApplicationHandlers method to register new handler: MigrateCorrespondenceHandler.
src/Altinn.Correspondence.Application/Errors.cs Added new error definition InvalidPartyId with specific error code and message.
src/Altinn.Correspondence.Application/GetCorrespondenceOverview/LegacyGetCorrespondenceOverviewHandler.cs Changed Process method return type to OneOf<LegacyGetCorrespondenceOverviewResponse, Error> and refined error handling.
src/Altinn.Correspondence.Application/GetCorrespondenceOverview/LegacyGetCorrespondenceOverviewResponse.cs Introduced LegacyGetCorrespondenceOverviewResponse class with additional properties for user permissions and document status.
src/Altinn.Correspondence.Core/Repositories/IAltinnAuthorizationService.cs Added method CheckUserAccessAndGetMinimumAuthLevel to retrieve the minimum authorization level for a user.
src/Altinn.Correspondence.Integrations/Altinn/Authorization/AltinnAuthorizationDevService.cs Implemented CheckUserAccessAndGetMinimumAuthLevel method returning a fixed value of 3.
src/Altinn.Correspondence.Integrations/Altinn/Authorization/AltinnAuthorizationService.cs Refactored CheckUserAccess method and added CheckMigrationAccess method for enhanced user access checks.
src/Altinn.Correspondence.Integrations/Idporten/IdPortenXacmlMapper.cs Added GetMinimumAuthLevel method to calculate the minimum authentication level from XacmlJsonResponse.
src/Altinn.Correspondence.API/Models/LegacyCorrespondenceItemExt.cs Updated property name from MinimumAuthenticationlevel to MinimumAuthenticationLevel for consistency.
src/Altinn.Correspondence.Application/GetCorespondences/LegacyGetCorrespondencesHandler.cs Updated property name from MinimumAuthenticationlevel to MinimumAuthenticationLevel and refined error handling logic.
src/Altinn.Correspondence.Application/GetCorespondences/LegacyGetCorrespondencesResponse.cs Updated property name from MinimumAuthenticationlevel to MinimumAuthenticationLevel for consistency.

Possibly related PRs

Suggested labels

kind/enhancement

Suggested reviewers

  • CelineTrammi
  • RagnarFatland-Avanade

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@Andreass2 Andreass2 added kind/feature-request New feature or request ignore-for-release pull request wont be included in release notes labels Nov 4, 2024
@Andreass2 Andreass2 marked this pull request as ready for review November 4, 2024 14:49
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🧹 Outside diff range and nitpick comments (15)
src/Altinn.Correspondence.Application/GetCorrespondenceOverview/LegacyGetCorrespondenceOverviewResponse.cs (2)

8-12: Add XML documentation for public properties.

Since these properties are part of a public API, they should be documented with XML comments to improve maintainability and provide better IntelliSense support.

+    /// <summary>
+    /// Gets or sets a value indicating whether the correspondence can be deleted.
+    /// </summary>
     public bool AllowDelete { get; set; }

+    /// <summary>
+    /// Gets or sets a value indicating whether the user is authorized to write.
+    /// </summary>
     public bool AuthorizedForWrite { get; set; }

+    /// <summary>
+    /// Gets or sets a value indicating whether the user is authorized to sign.
+    /// </summary>
     public bool AuthorizedForSign { get; set; }

+    /// <summary>
+    /// Gets or sets the date and time when the correspondence was archived.
+    /// </summary>
     public DateTimeOffset? Archived { get; set; }

+    /// <summary>
+    /// Gets or sets the minimum authentication level required.
+    /// </summary>
     public int MinimumAuthenticationlevel { get; set; }

12-12: Consider adding validation for MinimumAuthenticationlevel.

The MinimumAuthenticationlevel property should have validation to ensure it contains a valid authentication level value. Consider using an enum or adding range validation.

-    public int MinimumAuthenticationlevel { get; set; }
+    private int _minimumAuthenticationLevel;
+    public int MinimumAuthenticationlevel
+    {
+        get => _minimumAuthenticationLevel;
+        set
+        {
+            if (value < 0)
+            {
+                throw new ArgumentOutOfRangeException(nameof(value), "Authentication level cannot be negative.");
+            }
+            _minimumAuthenticationLevel = value;
+        }
+    }

Alternatively, consider using an enum:

public enum AuthenticationLevel
{
    None = 0,
    Level1 = 1,
    Level2 = 2,
    Level3 = 3,
    Level4 = 4
}

public AuthenticationLevel MinimumAuthenticationlevel { get; set; }
src/Altinn.Correspondence.Core/Repositories/IAltinnAuthorizationService.cs (2)

8-8: Add XML documentation for the new method.

Please add XML documentation to describe the method's purpose, parameters, return value, and possible exceptions. This will help maintain consistency with C# best practices and improve code maintainability.

+    /// <summary>
+    /// Checks user access and retrieves the minimum authentication level required for the specified resource.
+    /// </summary>
+    /// <param name="resourceId">The ID of the resource to check access for.</param>
+    /// <param name="rights">List of access levels to check against.</param>
+    /// <param name="cancellationToken">Optional cancellation token.</param>
+    /// <param name="recipientOrgNo">Optional recipient organization number.</param>
+    /// <returns>The minimum authentication level if access is granted, null otherwise.</returns>
     Task<int?> CheckUserAccessAndGetMinimumAuthLevel(string resourceId, List<ResourceAccessLevel> rights, CancellationToken cancellationToken = default, string? recipientOrgNo = null);

8-8: Consider splitting the method responsibilities.

The method currently combines two distinct responsibilities: checking access and retrieving the authentication level. While this might be more efficient in terms of API calls, it could make the interface less flexible and harder to maintain.

Consider these alternatives:

  1. Keep the current implementation if the two operations are always needed together and performance is critical.
  2. Split into separate methods if they might need to be used independently:
Task<bool> CheckUserAccess(...);
Task<int?> GetMinimumAuthLevel(...);

The current implementation is acceptable if you confirm that:

  • These operations are always performed together
  • The combined operation provides significant performance benefits
  • The implementation doesn't complicate the authorization service's logic
src/Altinn.Correspondence.API/Models/LegacyCorrespondenceOverviewExt.cs (1)

7-11: Enhance class documentation for authentication context.

While the documentation is present, it could be more descriptive about the class's role in authentication and its relationship with the A2 component.

Consider expanding the documentation:

 /// <summary>
-/// An object representing an overview of a correspondence for the legacy API    
+/// An object representing an overview of a correspondence for the legacy API, extending the base overview
+/// with additional authentication-related properties required for the A2 component integration.
+/// This class supports the enhanced authentication process through PDP requests.
 /// </summary>
src/Altinn.Correspondence.API/Mappers/LegacyCorrespondenceOverviewMapper.cs (2)

37-37: Fix property name casing.

The property name "MinimumAuthenticationlevel" should be "MinimumAuthenticationLevel" to follow C# naming conventions.

-            MinimumAuthenticationlevel = correspondenceOverview.MinimumAuthenticationlevel,
+            MinimumAuthenticationLevel = correspondenceOverview.MinimumAuthenticationLevel,

11-39: Consider using AutoMapper for complex mappings.

The current manual mapping approach could become hard to maintain as the model grows. Consider using AutoMapper to reduce boilerplate code and potential mapping errors.

Example implementation:

private static IMapper _mapper;

static LegacyCorrespondenceOverviewMapper()
{
    var config = new MapperConfiguration(cfg => 
    {
        cfg.CreateMap<LegacyGetCorrespondenceOverviewResponse, LegacyCorrespondenceOverviewExt>()
           .ForMember(dest => dest.Content, opt => 
                opt.MapFrom(src => CorrespondenceContentMapper.MapToExternal(src.Content)))
           .ForMember(dest => dest.ReplyOptions, opt => 
                opt.MapFrom(src => CorrespondenceReplyOptionsMapper.MapListToExternal(src.ReplyOptions)))
           // ... other complex mappings
    });
    
    _mapper = config.CreateMapper();
}

internal static LegacyCorrespondenceOverviewExt MapToExternal(LegacyGetCorrespondenceOverviewResponse correspondenceOverview)
{
    return _mapper.Map<LegacyCorrespondenceOverviewExt>(correspondenceOverview);
}
src/Altinn.Correspondence.Application/DependencyInjection.cs (1)

Line range hint 1-72: Consider improving section organization.

To enhance maintainability and clarity, consider:

  1. Using region directives or comments to clearly separate sections
  2. Keeping related handlers together
  3. Following a consistent registration pattern within each section

Example structure:

public static void AddApplicationHandlers(this IServiceCollection services)
{
    // Core Handlers
    #region Attachment Handlers
    services.AddScoped<InitializeAttachmentHandler>();
    // ... other attachment handlers
    #endregion

    #region Correspondence Handlers
    services.AddScoped<InitializeCorrespondencesHandler>();
    // ... other correspondence handlers
    #endregion

    #region Legacy Handlers
    services.AddScoped<LegacyGetCorrespondencesHandler>();
    services.AddScoped<LegacyGetCorrespondenceOverviewHandler>();
    services.AddScoped<LegacyGetCorrespondenceHistoryHandler>();
    #endregion

    // ... other sections
}
src/Altinn.Correspondence.API/Controllers/LegacyCorrespondenceController.cs (2)

Line range hint 73-73: Resolve return type uncertainty in GetCorrespondenceHistory

There's a TODO comment questioning whether the return type should be LegacyCorrespondenceHistoryExt. This should be resolved before merging.

Would you like me to help analyze the appropriate return type based on the codebase usage patterns?


Line range hint 1-24: Add automated tests as mentioned in PR objectives

The PR objectives mention that automated tests haven't been added. Consider adding tests for:

  1. Authentication/PDP request flow
  2. Legacy mapper implementations
  3. Error handling scenarios

Would you like assistance in generating the test implementations?

src/Altinn.Correspondence.Application/Errors.cs (1)

57-57: Consider enhancing the error message for better troubleshooting.

The implementation follows the established pattern and uses appropriate error code sequencing and HTTP status. However, the error message could be more descriptive to aid in troubleshooting.

Consider this enhancement:

-    public static Error InvalidPartyId = new Error(49, "Invalid partyId", HttpStatusCode.BadRequest);
+    public static Error InvalidPartyId = new Error(49, "The provided partyId is invalid or does not exist", HttpStatusCode.BadRequest);
src/Altinn.Correspondence.Integrations/Altinn/Authorization/AltinnAuthorizationService.cs (4)

48-55: Refactor the CheckUserAccess method to improve readability and maintainability.

Consider extracting the validation logic into a separate method to make the code more readable and maintainable. This will also help in reusing the validation logic in other methods.

public async Task<bool> CheckUserAccess(string resourceId, List<ResourceAccessLevel> rights, CancellationToken cancellationToken = default, string? recipientOrgNo = null)
{
    var user = _httpContextAccessor.HttpContext?.User;
    var validationResult = await ValidateCheckUserAccess(user, resourceId, cancellationToken);
    if (validationResult.HasValue)
    {
        return validationResult.Value;
    }

    var responseContent = await CheckUserAccess(user, rights, resourceId, recipientOrgNo, cancellationToken);
    if (responseContent is null)
    {
        return false;
    }

    return ValidateAuthorizationResponse(responseContent, user);
}

private async Task<bool?> ValidateCheckUserAccess(ClaimsPrincipal? user, string resourceId, CancellationToken cancellationToken)
{
    if (_httpClient.BaseAddress is null)
    {
        _logger.LogWarning("Authorization service disabled");
        return true;
    }

    var serviceOwnerId = await _resourceRepository.GetServiceOwnerOfResource(resourceId, cancellationToken);
    if (string.IsNullOrWhiteSpace(serviceOwnerId))
    {
        _logger.LogWarning("Service owner not found for resource");
        return false;
    }

    if (user is null)
    {
        _logger.LogError("Unexpected null value. User was null when checking access to resource");
        return false;
    }

    return null;
}

58-73: Consider adding XML documentation comments for the new CheckUserAccessAndGetMinimumAuthLevel method.

Adding XML documentation comments will help other developers understand the purpose, parameters, and return value of this method.

/// <summary>
/// Checks if the user has access to the specified resource and returns the minimum authentication level.
/// </summary>
/// <param name="resourceId">The ID of the resource to check access for.</param>
/// <param name="rights">The list of resource access levels to check.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="recipientOrgNo">The recipient organization number (optional).</param>
/// <returns>The minimum authentication level if the user has access, otherwise null.</returns>
public async Task<int?> CheckUserAccessAndGetMinimumAuthLevel(string resourceId, List<ResourceAccessLevel> rights, CancellationToken cancellationToken = default, string? recipientOrgNo = null)
{
    // ...
}

75-88: Consider adding logging for the CheckMigrationAccess method.

Adding logging statements will help in monitoring and debugging the migration access checks.

public async Task<bool> CheckMigrationAccess(string resourceId, List<ResourceAccessLevel> rights, CancellationToken cancellationToken = default)
{
    if (_hostEnvironment.IsDevelopment())
    {
        _logger.LogInformation("Migration access granted in development environment.");
        return true;
    }

    var serviceOwnerId = await _resourceRepository.GetServiceOwnerOfResource(resourceId, cancellationToken);
    if (string.IsNullOrWhiteSpace(serviceOwnerId))
    {
        _logger.LogWarning("Service owner not found for resource. Migration access denied.");
        return false;
    }

    _logger.LogInformation("Migration access granted for resource with service owner.");
    return true;
}

110-125: Consider renaming the CheckUserAccess method to avoid confusion with the public CheckUserAccess method.

Since this method is a private helper method, renaming it to something like GetUserAccessResponse or FetchUserAccessResponse would help differentiate it from the public method and clarify its purpose.

private async Task<XacmlJsonResponse?> GetUserAccessResponse(ClaimsPrincipal user, List<ResourceAccessLevel> rights, string resourceId, string? recipientOrgNo, CancellationToken cancellationToken)
{
    // ...
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 488df11 and 40b3f0b.

📒 Files selected for processing (11)
  • src/Altinn.Correspondence.API/Controllers/LegacyCorrespondenceController.cs (2 hunks)
  • src/Altinn.Correspondence.API/Mappers/LegacyCorrespondenceOverviewMapper.cs (1 hunks)
  • src/Altinn.Correspondence.API/Models/LegacyCorrespondenceOverviewExt.cs (1 hunks)
  • src/Altinn.Correspondence.Application/DependencyInjection.cs (1 hunks)
  • src/Altinn.Correspondence.Application/Errors.cs (1 hunks)
  • src/Altinn.Correspondence.Application/GetCorrespondenceOverview/LegacyGetCorrespondenceOverviewHandler.cs (4 hunks)
  • src/Altinn.Correspondence.Application/GetCorrespondenceOverview/LegacyGetCorrespondenceOverviewResponse.cs (1 hunks)
  • src/Altinn.Correspondence.Core/Repositories/IAltinnAuthorizationService.cs (1 hunks)
  • src/Altinn.Correspondence.Integrations/Altinn/Authorization/AltinnAuthorizationDevService.cs (1 hunks)
  • src/Altinn.Correspondence.Integrations/Altinn/Authorization/AltinnAuthorizationService.cs (2 hunks)
  • src/Altinn.Correspondence.Integrations/Idporten/IdPortenXacmlMapper.cs (1 hunks)
🧰 Additional context used
📓 Learnings (1)
src/Altinn.Correspondence.Application/DependencyInjection.cs (1)
Learnt from: CelineTrammi
PR: Altinn/altinn-correspondence#413
File: src/Altinn.Correspondence.Application/DependencyInjection.cs:0-0
Timestamp: 2024-10-29T13:40:14.651Z
Learning: In Altinn.Correspondence.Application, handlers with similar names—such as UploadAttachmentHandler, GetAttachmentDetailsHandler, GetAttachmentOverviewHandler, and PurgeAttachmentHandler—may have multiple distinct implementations and are intentionally registered separately in DependencyInjection.cs.
🪛 GitHub Check: CodeQL
src/Altinn.Correspondence.Application/GetCorrespondenceOverview/LegacyGetCorrespondenceOverviewHandler.cs

[failure] 35-35: User-controlled bypass of sensitive method
This condition guards a sensitive action, but a user-provided value controls it.
This condition guards a sensitive action, but a user-provided value controls it.


[failure] 35-35: User-controlled bypass of sensitive method
This condition guards a sensitive action, but a user-provided value controls it.


[failure] 35-35: User-controlled bypass of sensitive method
This condition guards a sensitive action, but a user-provided value controls it.

🔇 Additional comments (19)
src/Altinn.Correspondence.Application/GetCorrespondenceOverview/LegacyGetCorrespondenceOverviewResponse.cs (1)

6-7: LGTM! Class declaration follows proper conventions.

The class name and inheritance structure align well with the legacy correspondence overview enhancement objective.

src/Altinn.Correspondence.Integrations/Altinn/Authorization/AltinnAuthorizationDevService.cs (1)

18-21: ⚠️ Potential issue

Add documentation and development-only warnings for the mock implementation.

The hardcoded authentication level of 3 in this development service could be dangerous if accidentally used in production. Consider:

  1. Adding XML documentation to explain this is a development-only implementation
  2. Adding a warning log when this mock method is called
  3. Documenting why level 3 was chosen as the mock value

Here's a suggested improvement:

+        /// <summary>
+        /// Development-only implementation that returns a mock authentication level.
+        /// WARNING: This should never be used in production as it bypasses real authorization checks.
+        /// </summary>
+        /// <returns>Always returns authentication level 3 for development purposes.</returns>
         public Task<int?> CheckUserAccessAndGetMinimumAuthLevel(string resourceId, List<ResourceAccessLevel> rights, CancellationToken cancellationToken = default, string? recipientOrgNo = null)
         {
+            // TODO: Add warning log that this development implementation is being used
             return Task.FromResult((int?)3);
         }

Let's verify if there are any production configurations that might accidentally use this development service:

✅ Verification successful

Development service is properly controlled by configuration

The mock implementation is safe as it's only used in development scenarios. The service registration in DependencyInjection.cs shows that AltinnAuthorizationDevService is only registered when maskinportenSettings.ClientId is empty or null, which is the case in:

  • Development environment (empty ClientId in appsettings.Development.json)
  • Test scenarios (CustomWebApplicationFactory)

In production, when MaskinportenSettings.ClientId is configured, the real AltinnAuthorizationService is registered instead.

While the original review's documentation suggestions are still valuable for clarity, this is not a critical issue as the development service cannot be accidentally used in production.

Suggested improvements remain valid but optional:

+        /// <summary>
+        /// Development-only implementation that returns a mock authentication level.
+        /// This implementation is only used when MaskinportenSettings.ClientId is not configured.
+        /// </summary>
         public Task<int?> CheckUserAccessAndGetMinimumAuthLevel(string resourceId, List<ResourceAccessLevel> rights, CancellationToken cancellationToken = default, string? recipientOrgNo = null)
         {
             return Task.FromResult((int?)3);
         }
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for service registration of AltinnAuthorizationDevService
rg -l "AltinnAuthorizationDevService" | grep -i "startup\|program\|configuration"

Length of output: 81


Script:

#!/bin/bash
# Let's try a broader search to understand where this service is used and registered
rg -l "AltinnAuthorizationDevService"

Length of output: 264


Script:

#!/bin/bash
# Search for any Program.cs or Startup.cs files that might contain service registration
fd "Program.cs|Startup.cs"

Length of output: 69


Script:

#!/bin/bash
# Search for any configuration or DI setup related to authorization services
rg -i "services\.add.*authorization" -A 3 -B 3

Length of output: 5932


Script:

#!/bin/bash
# Check if there are any environment-specific configurations
fd -e json "appsettings"

Length of output: 130


Script:

#!/bin/bash
# Let's check the DependencyInjection.cs to understand how the dev service is configured
cat src/Altinn.Correspondence.Integrations/DependencyInjection.cs

Length of output: 4240


Script:

#!/bin/bash
# Let's also check the appsettings.Development.json to see if there's any configuration that controls this
cat src/Altinn.Correspondence.API/appsettings.Development.json

Length of output: 1417

src/Altinn.Correspondence.API/Models/LegacyCorrespondenceOverviewExt.cs (1)

1-6: LGTM! Clean namespace organization.

The using directives and namespace declaration follow proper conventions.

src/Altinn.Correspondence.API/Mappers/LegacyCorrespondenceOverviewMapper.cs (3)

1-5: LGTM! Clean imports following architecture boundaries.

The imports are minimal, focused, and properly organized according to clean architecture principles.


7-8: LGTM! Appropriate class design.

The class is correctly designed as an internal static mapper, following the single responsibility principle.


37-38: Validate authentication-related properties.

Given that this PR focuses on authentication enhancements, these properties should be validated to ensure security requirements are met.

src/Altinn.Correspondence.API/Controllers/LegacyCorrespondenceController.cs (3)

Line range hint 95-107: LGTM: GetCorrespondences implementation

The method correctly uses the legacy mapper and maintains proper error handling.


64-64: Verify LegacyCorrespondenceOverviewMapper implementation

The mapper has been renamed from CorrespondenceOverviewMapper to LegacyCorrespondenceOverviewMapper. Let's ensure the new mapper is properly implemented with all required properties mentioned in the AI summary (AllowDelete, AuthorizedForSign, MinimumAuthenticationlevel).

#!/bin/bash
# Check if the new mapper exists and contains required properties
ast-grep --pattern 'class LegacyCorrespondenceOverviewMapper {
  $$$
  MapToExternal($_) {
    $$$
  }
}'

Line range hint 1-24: Missing PDP request implementation mentioned in PR objectives

The PR objectives mention adding a PDP request for authentication, but the implementation is not visible in the controller. Ensure that the PDP request is properly implemented for secure authentication handling.

Let's check if PDP implementation exists elsewhere:

src/Altinn.Correspondence.Application/Errors.cs (1)

57-57: Verify error usage in authentication flow.

Since this error is part of the authentication enhancement, let's verify its integration.

✅ Verification successful

Error is properly integrated in authentication flow

The InvalidPartyId error is correctly used in the LegacyGetCorrespondenceOverviewHandler where it validates the party ID before proceeding with the correspondence overview request. The validation checks for invalid values (0 or int.MinValue) and returns the error appropriately.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for InvalidPartyId usage to ensure it's properly integrated
echo "Searching for InvalidPartyId usage..."
rg -l "InvalidPartyId" --type cs

# Search for related party validation logic
echo -e "\nSearching for party validation logic..."
rg "partyId.*invalid" --type cs -i

Length of output: 553


Script:

#!/bin/bash
# Let's check the usage context in LegacyGetCorrespondenceOverviewHandler.cs
echo "Checking InvalidPartyId usage context in handler:"
rg "InvalidPartyId" -B 5 -A 5 src/Altinn.Correspondence.Application/GetCorrespondenceOverview/LegacyGetCorrespondenceOverviewHandler.cs

# Let's also check if there are any party validation methods
echo -e "\nChecking for party validation methods:"
ast-grep --pattern 'private $_ $_($$$) {
  $$$
  partyId
  $$$
}'

Length of output: 952

src/Altinn.Correspondence.Integrations/Idporten/IdPortenXacmlMapper.cs (2)

131-160: ⚠️ Potential issue

Add security validations and audit logging.

For security-critical code:

  1. Add null checks for input parameters
  2. Add audit logging for authorization decisions
  3. Consider making the class internal unless public access is required

Apply these security improvements:

+using Microsoft.Extensions.Logging;

 public static int? GetMinimumAuthLevel(XacmlJsonResponse response, ClaimsPrincipal user)
 {
+    if (response == null)
+        throw new ArgumentNullException(nameof(response));
+    if (user == null)
+        throw new ArgumentNullException(nameof(user));
+
     int? minimumAuthLevel = null;
     foreach (var result in response.Response)
     {
         if (!result.Decision.Equals(XacmlContextDecision.Permit.ToString()))
         {
+            _logger.LogInformation("Authorization denied for user {UserId}", user.Identity?.Name);
             return null;
         }

Let's check for existing security measures:

#!/bin/bash
# Check for existing audit logging
rg -B 5 "LogInformation|LogWarning|LogError" --type cs

# Check for other security validations
ast-grep --pattern 'throw new ArgumentNullException($name)'

131-160: Document relationship with ValidateIdportenAuthorizationResponse.

The new method extracts minimum auth level while ValidateIdportenAuthorizationResponse validates it. Consider:

  1. Adding XML documentation to clarify the relationship
  2. Potentially refactoring to share common obligation extraction logic
  3. Adding unit tests to verify consistent behavior

Let's verify the usage pattern:

src/Altinn.Correspondence.Application/GetCorrespondenceOverview/LegacyGetCorrespondenceOverviewHandler.cs (6)

12-12: LGTM!

The class name change from GetCorrespondenceOverviewHandler to LegacyGetCorrespondenceOverviewHandler is appropriate given the focus on legacy correspondence overview in this update.


33-33: LGTM!

The change in the return type of the Process method from OneOf<GetCorrespondenceOverviewResponse, Error> to OneOf<LegacyGetCorrespondenceOverviewResponse, Error> aligns with the introduction of the new LegacyGetCorrespondenceOverviewResponse class, providing a more specific response type for the legacy correspondence overview.


37-37: LGTM!

The introduction of the Errors.InvalidPartyId error return case provides a more specific and informative error message when the PartyId is invalid, improving error handling and clarity.


43-43: LGTM!

The error return case Errors.CouldNotFindOrgNo is appropriate when the userParty is null or both the SSN and OrgNumber are empty, indicating that the organizational number could not be found for the given party.


50-54: LGTM!

The addition of the CheckUserAccessAndGetMinimumAuthLevel method call to the IAltinnAuthorizationService interface enhances the user access check by retrieving the minimum authentication level required for accessing the correspondence. If the required level is not met, the method now returns Errors.LegacyNoAccessToCorrespondence, providing a more specific error for unauthorized access scenarios.


Line range hint 104-131: LGTM!

The construction of the LegacyGetCorrespondenceOverviewResponse object has been updated to include additional properties such as MinimumAuthenticationlevel, AuthorizedForSign, DueDateTime, AllowDelete, Archived, and PropertyList. These changes enhance the detail and specificity of the response provided by the handler, aligning with the requirements of the legacy correspondence overview.

src/Altinn.Correspondence.Integrations/Altinn/Authorization/AltinnAuthorizationService.cs (1)

Line range hint 89-108: LGTM!

The ValidateCheckUserAccess method encapsulates the validation logic nicely and improves the readability of the CheckUserAccess method.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (6)
src/Altinn.Correspondence.Application/GetCorespondences/LegacyGetCorrespondencesHandler.cs (3)

Line range hint 141-146: Implementation required: Add resource access and authorization checks

The TODO comments indicate missing critical functionality:

  1. Resource access verification for parties
  2. Multi-request authorization using PDP
  3. Authentication level population

These are core requirements mentioned in the PR objectives but are not implemented yet.

Would you like assistance in implementing:

  1. Resource access verification using the Resource Registry API?
  2. Multi-request authorization using the Authorization API?
  3. Integration tests for the new authorization flow?

Line range hint 39-45: Improve error handling for party validation

The current error handling uses generic messages and needs improvement:

  1. Errors.CouldNotFindOrgNo is used for multiple different scenarios
  2. TODO comments indicate incomplete error handling

Consider implementing specific error types:

-            return Errors.CouldNotFindOrgNo; // TODO: Update to better error message
+            return Errors.InvalidPartyId(request.OnbehalfOfPartyId, "OnbehalfOfPartyId cannot be 0 or minimum value");

-            return Errors.CouldNotFindOrgNo; // TODO: Update to better error message
+            return Errors.PartyNotFound(request.OnbehalfOfPartyId, "Party must have either SSN or OrgNumber");

Based on the shell script results, I can now provide a final response:

Authentication and Authorization Implementation Required

The review comment is accurate. The code shows several authentication-related issues:

  1. Authentication level is hardcoded to 0 in multiple places:

    • LegacyGetCorrespondencesHandler.cs: MinimumAuthenticationLevel = 0, // Insert from response from PDP multirequest
    • LegacyGetCorrespondenceHistoryHandler.cs: AuthenticationLevel = 0, // TODO: Get authentication level
  2. The codebase has proper authentication infrastructure in place:

    • JWT Bearer authentication is configured
    • OpenID Connect is implemented
    • PDP (Policy Decision Point) integration exists
    • Authentication level validation logic exists in IdPortenXacmlMapper.cs and DialogTokenXacmlMapper.cs
  3. The TODO comments accurately identify the missing implementation:

    // TODO: Authorize each correspondence using multirequests
    //  https://docs.altinn.studio/authorization/guides/xacml/#request-for-multiple-decisions
    //  https://docs.altinn.studio/api/authorization/spec/#/Decision/post_authorize
    

The authentication level should be obtained from PDP responses instead of being hardcoded, and proper authorization checks need to be implemented using the existing infrastructure.

🔗 Analysis chain

Line range hint 1-146: PR Objectives Alignment Check

This implementation doesn't fully meet the PR objectives:

  1. The PDP request for authentication is not implemented
  2. Authentication level is hardcoded
  3. Error handling needs improvement
  4. Tests are missing as noted in PR description

Consider implementing these requirements before merging this PR to ensure proper authentication and authorization.

Let's verify test coverage:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for test files related to this handler
fd -e cs -e cs "Test|Spec" | rg -i "LegacyGetCorrespondences"

Length of output: 61


Script:

#!/bin/bash
# Let's first check if there are any test files in the repository
fd -e cs "Test" -t f

# Then let's check for any PDP/authentication related code
rg -i "pdp|authentication" -A 5 -B 5 src/

# Let's also check for any TODO comments related to authentication
rg "TODO.*auth" src/

Length of output: 76359

src/Altinn.Correspondence.Integrations/Idporten/IdPortenXacmlMapper.cs (2)

131-157: Add XML documentation for better maintainability.

Since this method is public and plays a crucial role in authentication, consider adding XML documentation to describe its purpose, parameters, return value, and behavior.

+/// <summary>
+/// Extracts the minimum authentication level from the XACML response.
+/// </summary>
+/// <param name="response">The XACML response containing authorization decisions and obligations.</param>
+/// <param name="user">The claims principal representing the authenticated user.</param>
+/// <returns>The minimum required authentication level if found; null if unauthorized or no level specified.</returns>
 public static int? GetMinimumAuthLevel(XacmlJsonResponse response, ClaimsPrincipal user)

144-144: Extract the obligation category as a constant.

Consider extracting the magic string "urn:altinn:minimum-authenticationlevel" as a private constant at the class level for better maintainability and reusability.

+private const string MinimumAuthLevelCategory = "urn:altinn:minimum-authenticationlevel";

-XacmlJsonAttributeAssignment? obligation = GetObligation("urn:altinn:minimum-authenticationlevel", obligations);
+XacmlJsonAttributeAssignment? obligation = GetObligation(MinimumAuthLevelCategory, obligations);
src/Altinn.Correspondence.API/Mappers/LegacyCorrespondenceOverviewMapper.cs (1)

11-11: Use camelCase for local variable names

According to C# naming conventions, local variables should be in camelCase. Please rename Correspondence to correspondence.

Apply this diff to correct the variable name:

-            var Correspondence = new LegacyCorrespondenceOverviewExt
+            var correspondence = new LegacyCorrespondenceOverviewExt
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 40b3f0b and 94f1460.

📒 Files selected for processing (9)
  • src/Altinn.Correspondence.API/Mappers/LegacyCorrespondenceOverviewMapper.cs (1 hunks)
  • src/Altinn.Correspondence.API/Models/LegacyCorrespondenceItemExt.cs (1 hunks)
  • src/Altinn.Correspondence.API/Models/LegacyCorrespondenceOverviewExt.cs (1 hunks)
  • src/Altinn.Correspondence.Application/DependencyInjection.cs (1 hunks)
  • src/Altinn.Correspondence.Application/GetCorespondences/LegacyGetCorrespondencesHandler.cs (1 hunks)
  • src/Altinn.Correspondence.Application/GetCorespondences/LegacyGetCorrespondencesResponse.cs (1 hunks)
  • src/Altinn.Correspondence.Application/GetCorrespondenceOverview/LegacyGetCorrespondenceOverviewHandler.cs (4 hunks)
  • src/Altinn.Correspondence.Application/GetCorrespondenceOverview/LegacyGetCorrespondenceOverviewResponse.cs (1 hunks)
  • src/Altinn.Correspondence.Integrations/Idporten/IdPortenXacmlMapper.cs (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • src/Altinn.Correspondence.API/Models/LegacyCorrespondenceItemExt.cs
  • src/Altinn.Correspondence.Application/GetCorespondences/LegacyGetCorrespondencesResponse.cs
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/Altinn.Correspondence.API/Models/LegacyCorrespondenceOverviewExt.cs
  • src/Altinn.Correspondence.Application/DependencyInjection.cs
  • src/Altinn.Correspondence.Application/GetCorrespondenceOverview/LegacyGetCorrespondenceOverviewHandler.cs
  • src/Altinn.Correspondence.Application/GetCorrespondenceOverview/LegacyGetCorrespondenceOverviewResponse.cs
🧰 Additional context used
📓 Learnings (1)
src/Altinn.Correspondence.Application/GetCorespondences/LegacyGetCorrespondencesHandler.cs (1)
Learnt from: CelineTrammi
PR: Altinn/altinn-correspondence#413
File: src/Altinn.Correspondence.Application/GetCorrespondenceHistory/LegacyGetCorrespondenceHistoryResponse.cs:17-21
Timestamp: 2024-10-29T13:10:17.164Z
Learning: The `PartyId` and `AuthenticationLevel` properties in the `LegacyUser` class (in `src/Altinn.Correspondence.Application/GetCorrespondenceHistory/LegacyGetCorrespondenceHistoryResponse.cs`) are still under development, and the correct validation has not been determined yet.
🔇 Additional comments (2)
src/Altinn.Correspondence.Integrations/Idporten/IdPortenXacmlMapper.cs (1)

131-157: Implementation looks good!

The implementation is robust and secure:

  • Properly handles invalid decisions by returning null
  • Safely parses integer values using TryParse
  • Efficiently tracks minimum value
  • Gracefully handles missing or invalid obligations
src/Altinn.Correspondence.API/Mappers/LegacyCorrespondenceOverviewMapper.cs (1)

1-42: Code implementation is correct and follows best practices

The mapping function accurately maps all properties from the input object to the output object. The code is well-structured and maintains clarity.

Copy link
Collaborator

@CelineTrammi CelineTrammi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice to have some auth!

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (1)
src/Altinn.Correspondence.Integrations/Altinn/Authorization/AltinnAuthorizationService.cs (1)

110-125: Enhance error logging in AuthorizeRequest method.

While the error handling is good, consider adding more detailed logging for troubleshooting:

  1. Log the HTTP status code when the response is not successful
  2. Log the request details (excluding sensitive data) when authorization fails

Apply this diff to enhance logging:

         var response = await _httpClient.PostAsJsonAsync("authorization/api/v1/authorize", jsonRequest, cancellationToken);
         if (!response.IsSuccessStatusCode)
         {
+            _logger.LogError("Authorization request failed with status code: {StatusCode}", response.StatusCode);
             return null;
         }
         var responseContent = await response.Content.ReadFromJsonAsync<XacmlJsonResponse>(cancellationToken: cancellationToken);
         if (responseContent is null)
         {
-            _logger.LogError("Unexpected null or invalid json response from Authorization.");
+            _logger.LogError("Unexpected null or invalid json response from Authorization for resource: {ResourceId}", resourceId);
             return null;
         }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 9f93489 and b1be99f.

📒 Files selected for processing (1)
  • src/Altinn.Correspondence.Integrations/Altinn/Authorization/AltinnAuthorizationService.cs (2 hunks)
🔇 Additional comments (2)
src/Altinn.Correspondence.Integrations/Altinn/Authorization/AltinnAuthorizationService.cs (2)

58-73: ⚠️ Potential issue

Review hardcoded authentication level.

The method returns a hardcoded authentication level of 3 when validation passes. This might not be appropriate for all cases and could potentially bypass security requirements.

Let's verify if there are any configuration settings or constants defining the authentication levels:

Consider making the authentication level configurable or deriving it from the resource requirements instead of hardcoding it.


75-88: ⚠️ Potential issue

Review security implications and method naming.

The method has several concerns:

  1. It bypasses all security checks in development environment
  2. The method name suggests migration access checks, but it only verifies service owner existence
  3. No actual migration-specific access rules are being checked

Consider:

  1. Adding a configuration flag instead of relying on environment for security bypasses
  2. Implementing actual migration-specific access rules
  3. Renaming the method to better reflect its purpose, e.g., ValidateServiceOwnerAccess

Let's check for any migration-related configurations or rules:

✅ Verification successful

Let me analyze the search results. I can see that there is a comprehensive migration system in place:

  1. There's a dedicated MigrationController with proper authorization using the altinn:correspondence.migrate scope
  2. The CheckMigrationAccess method is part of a larger migration system that includes:
    • Migration repositories
    • Migration status tracking
    • Migration handlers for both correspondence and attachments
    • Proper authorization checks

Let me verify the actual implementation of authorization checks in development:


Based on the search results, I can now provide a comprehensive response about the security implications of the CheckMigrationAccess method:

Development bypass is consistent with application-wide security patterns

The development environment bypasses in the codebase follow a consistent pattern used for:

  1. Skipping malware scans in development (UploadHelper.cs)
  2. JWT lifetime validation (DependencyInjection.cs)
  3. Migration access checks (AltinnAuthorizationService.cs)

This is a standard practice in the codebase for development convenience, and other security-critical features follow the same pattern. The method's implementation is appropriate because:

  1. The bypass only affects development environments
  2. It's part of a proper migration system with dedicated authorization scopes (altinn:correspondence.migrate)
  3. The service owner validation provides a basic security check in production

The method name accurately reflects its purpose as it's part of a comprehensive migration system that includes:

  • Migration controllers and handlers
  • Migration status tracking
  • Proper authorization checks
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for migration-related code
rg -i "migration|migrate" --type cs

Length of output: 53166


Script:

#!/bin/bash
# Search for development environment checks in authorization services
rg -A 5 "IsDevelopment\(\)" --type cs

Length of output: 7157

@Andreass2 Andreass2 merged commit dce6a87 into main Nov 5, 2024
6 checks passed
@Andreass2 Andreass2 deleted the legacy/overview-auth! branch November 5, 2024 09:18
CelineTrammi pushed a commit that referenced this pull request Nov 5, 2024
* Initial functionality for legacy correspondenceOverview

* improvements

* better naming

* better text for api route

* add auth for legacy overview

* better error message

* fix variable names

* improve minAuthLevel function

* Better naming

---------

Co-authored-by: Hammerbeck <[email protected]>
CelineTrammi added a commit that referenced this pull request Nov 6, 2024
* Add logic for downloading attachment for A2 GUI

* null check fileName

* Checkout before using action (#423)

* Fix deploy permission (#425)

* Fix: Ensure correspondence is fetched before updating to Read or Confirmed (#427)

* fix: validate correspondence has been fetched before it can be read and confirmed

* update tests

* typo fix

* Handle potential null value for IsConfirmationNeeded

* reuse factory for client initialization

* rename testname

* add Fetched to statuses available for Recipient

* Legacy/overview auth! (#430)

* Initial functionality for legacy correspondenceOverview

* improvements

* better naming

* better text for api route

* add auth for legacy overview

* better error message

* fix variable names

* improve minAuthLevel function

* Better naming

---------

Co-authored-by: Hammerbeck <[email protected]>

* Missing reference to Github environment in CI/CD (#436)

* Add logic to check if user is recipient

* Fix deploy permission (#425)

* Fix: Ensure correspondence is fetched before updating to Read or Confirmed (#427)

* fix: validate correspondence has been fetched before it can be read and confirmed

* update tests

* typo fix

* Handle potential null value for IsConfirmationNeeded

* reuse factory for client initialization

* rename testname

* add Fetched to statuses available for Recipient

* Missing reference to Github environment in CI/CD (#436)

* remove duplicate and rewrite userClaim logic

* remove unused usings

* add norwegian org prefix to recipient check

---------

Co-authored-by: Roar Mjelde <[email protected]>
Co-authored-by: Andreas Hammerbeck <[email protected]>
Co-authored-by: Hammerbeck <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ignore-for-release pull request wont be included in release notes kind/feature-request New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants